/**
 ******************************************************************************
 * @file           : bsp_dht11.c
 * @brief          : DHT11 Temperature Humidity Sensor Driver (STM32F4xx)
 ******************************************************************************
 */

#include "./Devices/DHT11/bsp_dht11.h"
#include "./Devices/DHT11/bsp_dht11_config.h"

static void dht11_delay_us(uint16_t us)
{
    uint32_t cycles = us * 168 / 4;
    while (cycles--);
}

uint8_t dht11_init(void)
{
    GPIO_InitTypeDef gpio_init = {0};
    
    __HAL_RCC_GPIOA_CLK_ENABLE();
    
    gpio_init.Pin = DHT11_GPIO_PIN;
    gpio_init.Mode = GPIO_MODE_OUTPUT_OD;
    gpio_init.Pull = GPIO_PULLUP;
    gpio_init.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(DHT11_GPIO_PORT, &gpio_init);
    
    HAL_GPIO_WritePin(DHT11_GPIO_PORT, DHT11_GPIO_PIN, GPIO_PIN_SET);
    HAL_Delay(1000);
    
    log_i("DHT11 initialized");
    return 0;
}

void dht11_deinit(void)
{
    HAL_GPIO_DeInit(DHT11_GPIO_PORT, DHT11_GPIO_PIN);
}

uint8_t dht11_read_data(DHT11_Data_t *data)
{
    uint8_t buffer[5] = {0};
    uint8_t bit_count = 0;
    uint16_t timeout = 0;
    
    if (data == NULL)
    {
        return 1;
    }
    
    /* 发送启动信号 */
    HAL_GPIO_WritePin(DHT11_GPIO_PORT, DHT11_GPIO_PIN, GPIO_PIN_RESET);
    HAL_Delay(18);
    HAL_GPIO_WritePin(DHT11_GPIO_PORT, DHT11_GPIO_PIN, GPIO_PIN_SET);
    dht11_delay_us(30);
    
    /* 等待DHT11响应 */
    timeout = 1000;
    while (HAL_GPIO_ReadPin(DHT11_GPIO_PORT, DHT11_GPIO_PIN) && timeout--)
    {
        dht11_delay_us(1);
    }
    
    if (timeout == 0)
    {
        log_e("DHT11 no response");
        return 1;
    }
    
    /* 读取40位数据 */
    for (int i = 0; i < 40; i++)
    {
        timeout = 1000;
        while (!HAL_GPIO_ReadPin(DHT11_GPIO_PORT, DHT11_GPIO_PIN) && timeout--)
        {
            dht11_delay_us(1);
        }
        
        dht11_delay_us(30);
        
        if (HAL_GPIO_ReadPin(DHT11_GPIO_PORT, DHT11_GPIO_PIN))
        {
            buffer[i / 8] |= (1 << (7 - (i % 8)));
        }
        
        timeout = 1000;
        while (HAL_GPIO_ReadPin(DHT11_GPIO_PORT, DHT11_GPIO_PIN) && timeout--)
        {
            dht11_delay_us(1);
        }
    }
    
    data->humidity = buffer[0];
    data->temperature = buffer[2];
    
    return 0;
}
